package org.apache.axis2.json.rpc;

import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import org.apache.axis2.json.Utils.JsonConstant;
import org.apache.axis2.json.Utils.JsonMessageContext;
import org.apache.axis2.json.Utils.JsonUtils;
import org.apache.axis2.json.exception.Axis2JsonException;

import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;


public class JsonRPCMessageReceiver implements MessageReceiver , JsonConstant{

//    JsonReader reader ;
//    JsonWriter writer ;
//    JsonMessageContext inJson;
//    JsonMessageContext outJson;
//    private static final String DEFAULT_CHAR_SET = "UTF-8";



    @Override
    public void receive(JsonMessageContext inJson ,JsonMessageContext outJson) {
        initiateReaderAndWriter(inJson, outJson);
        try {
            invokeBusinessLogic(inJson , outJson);
        } catch (Axis2JsonException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (IOException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
    }

    public void initiateReaderAndWriter(JsonMessageContext inJson  , JsonMessageContext outJson){

        try {
            JsonReader reader = new JsonReader(new InputStreamReader(inJson.getInMsgStream() , inJson.getCharSet()));
            JsonWriter writer = new JsonWriter(new OutputStreamWriter(outJson.getOutMsgStream(),inJson.getCharSet()));
            inJson.setReader(reader);
            outJson.setWriter(writer);

        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    public void invokeBusinessLogic(JsonMessageContext inJson , JsonMessageContext outJson) throws Axis2JsonException, IOException {
        //TODO- handle request and response

        // Handle request
        processForOperatoin(inJson.getReader(), inJson);
        Class serviceClass = null;
        int paramCount=0;
        Object retObj;
        try {
            serviceClass = Class.forName(inJson.getSerivceName());
            Object serviceInst = serviceClass.newInstance();
            Method[] serviceMethods = serviceClass.getMethods();
            Method operation = getMethod(serviceMethods, inJson.getOperationName());
//            String [] paramNames= operation.
            Class[] paramClasses = operation.getParameterTypes();
            paramCount = paramClasses.length;


            retObj = JsonUtils.invokeServiceClass(inJson.getReader() , 
                    serviceInst , operation , paramClasses , paramCount );
            
            
            // handle response 
            
            outJson.setOperationName(inJson.getOperationName()+RESPONSE);

            JsonUtils.processResponse(outJson.getWriter() , operation ,retObj , outJson.getOperationName());


        } catch (ClassNotFoundException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (InstantiationException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (IllegalAccessException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (InvocationTargetException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
        
        
        


    }

    public String processForOperatoin(JsonReader reader , JsonMessageContext jsonMesCtx) throws IOException, Axis2JsonException {
            // TODO- get the operation name processing input message
        JsonToken token = reader.peek();
        if(token==JsonToken.BEGIN_OBJECT){
            reader.beginObject();
            String opName = reader.nextName();
            if (opName != null || ! opName.equalsIgnoreCase("")) {
                jsonMesCtx.setOperationName(opName);
                return opName;
            }else {
                throw new Axis2JsonException(INVALIED_OPERATION_NAME);
            }
        }else {
            throw new Axis2JsonException(MESSAGE_NOT_IN_CORRECT_FORMAT);
        }
        
    }


    public Method getMethod(Method[] methods, String methodName) {
        //TODO- find the given method by method name
        for (Method method : methods) {
            String mName = method.getName();
            if (mName.equals(methodName)) {
                return method;
            }
        }
        return null;
    }
}
